package game.controlling;
import java.io.Serializable;

import tools.Profiler;
import network.NetworkController;
import network.byteConversions.ByteConverter;
import network.dataFormats.NetworkPackage;

import game.Game;
import game.logic.GameLogic;
import game.logic.Player;
import game.objects.GameObject;
import game.objects.interfaces.Ownable;
/**
 * Handles controlling of objects. Keeps a list with players that exist in the game. Each player can be assigned a controller, which can be a local controller (the direct mouse and keyboard actions), a network controller which will get its actions sent across the network, from a local controller on a client or a AI-controller which will have its actions determined by a AI.
 * 
 * @author toni
 * 
 */
public class ControlHandling implements Serializable {
	private GameLogic logic;
	private Game game;
	private transient ControllerManager controllerManager;
	private transient KeyListener keyListener;
	public ControlHandling(Game g, GameLogic logic) {
		game = g;
		this.logic = logic;
		controllerManager = new ControllerManager();
	}
	public void handle() {
		Profiler.startGame();
		controllerManager.handle();
		controlAllObjects();
		handleAllObjects();
		Profiler.stopGame();
	}
	private void handleAllObjects() {
		for (int i = 0; i < game.numGameObjects; i++) {
			game.getGameObject(i).handle();
		}
	}
	private void controlAllObjects() {
		for (int i = 0; i < game.numGameObjects; i++) {
			GameObject o = game.getGameObject(i);
			if (o instanceof Ownable) {
				Ownable obj = (Ownable) o;
				Controller controller = getController(obj.getOwner());
				if (controller == null)
					continue;
				obj.control(controller);
			}
		}
	}
	private Controller getController(int playerId) {
		return controllerManager.get(playerId);
	}
	public void remPlayer(int playerId) {
		logic.remPlayer(logic.getPlayerById(playerId));
	}
	public void addPlayer(int gameId, int playerId) {
		if (!logic.containsPlayerId(playerId)) {
			logic.addPlayer(new Player(playerId));
		}
		setPlayerController(gameId, playerId);
	}
	private void setPlayerController(int gameId, int playerId) {
		Controller controller;
		if (gameId == playerId) { // This is the player that belongs to this
									// instance of the game.
			controller = new LocalController(keyListener);
		}
		else { // Somebody elses player
			controller = new NetworkController();
		}
		controllerManager.set(playerId, controller);
	}
	public void setUp(int gameId) {
		controllerManager = new ControllerManager();
		for (int i = 0; i < logic.numPlayers(); i++) {
			int id = logic.getPlayer(i).getId();
			setPlayerController(gameId, id);
		}
	}
	public void setKeyListener(KeyListener keyListener) {
		this.keyListener = keyListener;
		for (int i = 0; i < logic.numPlayers(); i++) {
			int id = logic.getPlayer(i).getId();
			Controller c = controllerManager.get(id);
			if (c instanceof LocalController) {
				LocalController t = ((LocalController) c);
				t.setKeyListener(keyListener);
			}
		}
	}
	private LocalController getLocalControler() {
		for (int i = 0; i < logic.numPlayers(); i++) {
			int id = logic.getPlayer(i).getId();
			Controller c = controllerManager.get(id);
			if (c instanceof LocalController) {
				return ((LocalController) c);
			}
		}
		return null;
	}
	public NetworkPackage getControlData(int packageId, float time) {
		LocalController c = getLocalControler();
		if (c == null) {
			return null;
		}
		return ControlData.create(c, game.network.id, packageId, time);
	}
	public void handleControlData(NetworkPackage p) {
		int idFrom = ByteConverter.bytesToInt(p.getData(), 0);
		assert (controllerManager.get(idFrom) instanceof NetworkController);
		ControlData.read((NetworkController) controllerManager.get(idFrom), p);
	}
}
